/*
 * в этом файле хранится главный класс Game, включающий поле игры и глобальные настройки правил
 */

/**
 * Созать экземпляр логики игры
 * @param {Properties} properties класс настроек 
 */
function Game(properties){
	
	this.list = []; // список объектов
	var prop = properties;
	var isRunning = false;
	var timer;
	
	/**
	 * 
	 */
	this.levelname = "level_name";
	/**
	 * 
	 */
	this.levelinfo = "level_info";
	/**
	 * Условия победы или проигрыша
	 * функция должна быть изменена при инициализации
	 * @return 0:продолжаем, -1:проигрыш, 1:победа
	 */
	this.condition = function(){
		return 0;
	}
	
	this.getProp = function(){
		return prop;
	}
	
	/**
	 * выполняется при возникновении победы
	 */
	this.win = function(){
		this.pauseGame();
		this.list = [];
		alert("You win!");
		return;
	}
	
	/**
	 * выполняется при возникновении поражения
	 */
	this.lose = function(){
		this.pauseGame();
		this.list = [];
		alert("You lose!");
		return;
	}
	
	/**
	 * Включить цикл выполнения
	 */
	this.playGame = function(){
		if (!isRunning) {
			var g = this;
			timer = setInterval(function(){ g.go(); }, prop.gameTimeOut);
			isRunning = true;
		}
	}
	
	/**
	 * Остановить цикл выполнения
	 */
	this.pauseGame = function(){
		if (isRunning) {
			clearInterval(timer);
			isRunning = false;
		}
	}
	
	
	/**
	 * выполнить шаг цикла
	 * @param {array} список объектов
	 */
	this.go = function(){
		switch (this.condition()) {
			case -1:
				this.lose();
				return;
			case 1:
				this.win();
				return;
			default:
				// двигать все
				for (var i = 0; i < this.list.length; i++) {
					move(this.list[i]);
				}
				// если пара пересекается, то инициировать всасывание
				for (var i = 0; i < this.list.length - 1; i++) {
					for (var j = i + 1; j < this.list.length; j++) {
						if (checkIntersec(this.list[i], this.list[j])) {
							absorb(this.list[i], this.list[j]);
							cleanList(this.list);
						}
					}
				}
		}
	}
	
	// удалить съеденые объекты
	function cleanList(list) {
		for (var i = 0; i < +list.length; i++) {
			if (list[i].rad <= 0) {
				for (var j = i; j < list.length - 1; j++) {
					list[j] = list[j+1];
				}
				list.pop();
			}
		}
	}
	
	/**
	 * Передвинуть объект в соответствии с его импульсом
	 * @param {Sphere} sph
	 */
	function move(sph) {
		// отскок
        if(sph.pos.x + sph.rad-1 >= prop.width && sph.imp.x > 0 ) {
			sph.imp.x = -sph.imp.x;
		}
		if(sph.pos.x - sph.rad-1 <= 0 && sph.imp.x < 0) {
            sph.imp.x = -sph.imp.x;
        }
        if(sph.pos.y + sph.rad-1 >= prop.height && sph.imp.y > 0) {
			sph.imp.y = -sph.imp.y;
		}
		if(sph.pos.y - sph.rad-1 <= 0 && sph.imp.y < 0) {
            sph.imp.y = -sph.imp.y;
        }
        // двигаем
        sph.pos.x += sph.imp.x;
		sph.pos.y += sph.imp.y;
        // учитываем трение
       	sph.imp.x = sph.imp.x*(1-prop.friction);
        sph.imp.y = sph.imp.y*(1-prop.friction);
    }
	
	/**
	 * Проверить, пересекаются ли объекты
	 * @param {Sphere} sph1
	 * @param {Sphere} sph2
	 * @return {boolean} 
	 */
	function checkIntersec(sph1, sph2) {
		var l = Math.sqrt(Math.pow(sph1.pos.x - sph2.pos.x, 2) + Math.pow(sph1.pos.y - sph2.pos.y, 2));
		return (l < (sph1.rad + sph2.rad));
	}
	
	/**
	 * провести расчет поглощения
	 * @param {Sphere} sph1
	 * @param {Sphere} sph2
	 */
	function absorb(sph1, sph2) {
	    // первая должна быть больше
	    if (sph1.rad < sph2.rad ) {
	        var buf = sph1;
	        sph1 = sph2;
	        sph2 = buf;
	    }
	    var r1 = sph1.rad;
	    var r2 = sph2.rad;
	    var r = Math.sqrt( Math.pow(sph1.pos.x - sph2.pos.x, 2) + Math.pow(sph1.pos.y - sph2.pos.y, 2) );
		if(r1 >= r) {
			sph1.rad = Math.pow(r1*r1*r1 + r2*r2*r2, 1/3);
			sph2.rad = 0;
		}else {
	    	sph1.rad = ( 3*r*r + Math.sqrt( - 3*r*r*r*r + 12*r*(r1*r1*r1 + r2*r2*r2) ) ) / (6*r);
	    	sph2.rad = r - sph1.rad;
		}     
	}
}
